#ifndef PRYN_MEDIATOR_H
#define PRYN_MEDIATOR_H

typedef struct PrynMediator PrynMediator;

#include <pryn/platform.h>

typedef PrynDList (PrynMediator) PrynMediatorList; ///< List of mediators.

#include <pryn/library.h>
#include <pryn/result.h>
#include <pryn/string.h>
#include <pryn/tag.h>

typedef PrynResult (*PrynMediatorEnableFunction) (PrynMediator *mediator); ///< Function signature for enabling a mediator, loading all plugins which can be mediated.

/** @defgroup PrynMediator PrynMediator C API
	@{ */

PrynImport (PrynResult, prynMediatorCreate, (PrynMediator **output, PrynLibrary *library, const PrynString *id))
	/**< @brief Create a new mediator.

	@param library The library that controls the mediator.
	@param[out] output Receives the new mediator, or 0 if the function fails.
	@param id A unique identifier of the mediator; the value is adopted, not copied.
	@returns #PrynResultSuccess or error code; see #PrynResult. */

PrynImport (PrynResult, prynMediatorDestroy, (PrynMediator *mediator))
	/**< @brief Completely destroy the mediator.

	All types and factories associated to the mediator will be destroyed, and by turn all components and values from those factories and types will be disassociated (see #prynComponentDisassociate and #prynValueDisassociate).

	@param mediator The mediator to destroy.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

PrynImport (PrynResult, prynMediatorEnable, (PrynMediator *mediator))
	/**< @brief Enable the mediator if it hasn't been already.

	This causes the mediator to load all the libraries it can or has been configured to load.

	@param mediator The mediator to enable.
	@returns #PrynResultSuccess if the mediator was loaded, #PrynResultDone if it has already been loaded, or an error; see #PrynResult. */

PrynImport (PrynResult, prynMediatorState, (PrynMediator *mediator, PrynState **output)) ///< Retrieve the state the mediator is from.
PrynImport (PrynResult, prynMediatorTags, (PrynMediator *mediator, PrynTagList **output)) ///< Retrieve the list of tags associated with the mediator.
PrynImport (PrynResult, prynMediatorLibrary, (PrynMediator *mediator, PrynLibrary **output)) ///< Retrieve the library this mediator is from.
PrynImport (PrynResult, prynMediatorName, (PrynMediator *mediator, PrynString *output)) ///< Retrieve the name of the mediator.
PrynImport (PrynResult, prynMediatorDescription, (PrynMediator *mediator, PrynString *output)) ///< Retrieve the description of the mediator.

PrynImport (PrynResult, prynMediatorSetName, (PrynMediator *mediator, const PrynString *value)) ///< Set the name of the mediator, adopting the value.
PrynImport (PrynResult, prynMediatorSetDescription, (PrynMediator *mediator, const PrynString *value)) ///< Set the description of the mediator, adopting the value.
PrynImport (PrynResult, prynMediatorSetEnableFunction, (PrynMediator *mediator, PrynMediatorEnableFunction enable)) ///< Set the enable function for the mediator.

/// Set the name of the mediator, adopting the literal value.
#define prynSetMediatorNameLiteral(MEDIATOR, VALUE) prynStringLiteralBlock (NAME, STRING, { prynMediatorSetName ((FACTORY), &STRING); })

/// Set the description of the mediator, adopting the literal value.
#define prynSetMediatorDescriptionLiteral(MEDIATOR, VALUE) prynStringLiteralBlock (NAME, STRING, { prynMediatorSetDescription ((FACTORY), &STRING); })

#ifdef PrynInternalStructs
/** @brief A mediator converts external plugins into components and pin types that can be transparently used by Pryn. */
struct PrynMediator
{
#ifdef PrynInternal
/** @name Internal fields
	These fields are not normally visible to clients, and it is recommended not to use them to maximise binary compatibility. To make them available, define PrynInternal.
	@{ */

	PrynCommonObject pCommonObject; ///< Common fields you'd expect in an object, like tags and monitors.
	PrynCommonResource pCommonResource; ///< Common fields you'd expect in a resource, like name and description.
	PrynMediator *pNext; ///< Next mediator or 0 if this is the last.
	PrynMediator *pPrevious; ///< Previous mediator or 0 if this is the first.
	PrynLibrary *pLibrary; ///< The library this mediator is defined within.

	PrynString pId; ///< A unique unchanging identifier of the mediator, such as "Pryn.Mediator.Photoshop".
	
	bool pEnabled; ///< Whether the mediator has been enabled.
	PrynMediatorEnableFunction pEnableFunction; ///< Enable the mediator, clearing to default parameters and loading all plugins that can be mediated.

/** @} */
#endif /* PrynInternal */

#if __cplusplus
	static inline PrynMediator *Create (PrynLibrary *library, const PrynString &id);
		/**< @brief Create a new mediator.

		@param library The library that controls the mediator.
		@param id A unique identifier of the mediator; the value is adopted, not copied.
		@returns The new mediator. */

	inline PrynResult checkError (PrynResult result) { return prynCheckErrorBase (state (), result); } ///< If the result is below zero, throw an error.

	inline bool enable () { return PrynIsTrue (checkError (prynMediatorEnable (this))); }
		/**< @brief Enable the mediator if it hasn't been already.

		This causes the mediator to load all the libraries it can or has been configured to load.

		@returns @b true if the mediator was loaded or @b false if it has already been loaded. */

/** @name Properties
@{ */

	PrynState *state () { PrynState *result; prynCheckErrorNull (prynMediatorState (this, &result)); return result; } ///< The state the mediator exists in.
	PrynTagList *tags () { PrynTagList *result; checkError (prynMediatorTags (this, &result)); return result; } ///< The tags associated with the mediator.
	PrynLibrary *library () { PrynLibrary *result; checkError (prynMediatorLibrary (this, &result)); return result; } ///< The library the mediator exists within.
	PrynString name () { PrynString result; checkError (prynMediatorName (this, &result)); return result; } ///< The name of the mediator.
	void name (const PrynString &value) { checkError (prynMediatorSetName (this, &value)); } ///< Set the name of the mediator; the value is adopted.
	PrynString description () { PrynString result; checkError (prynMediatorDescription (this, &result)); return result; } ///< The description of the mediator.
	void description (const PrynString &value) { checkError (prynMediatorSetDescription (this, &value)); } ///< Set the description of the mediator; the value is adopted.

#endif /* __cplusplus */
};
#endif /* PrynInternalStructs */

/** @} */ // (group)

#endif /* PRYN_MEDIATOR_H */
